use std::io;
use super::bytes_io::BytesIO;

impl std::io::Write for BytesIO {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        // todo: bytes::BytesMut
        let len_vec = self.bytes.len();
        let len_append = buf.len();
        let len_after = self.pos + len_append;

        if len_after <= len_vec {
            let len_write = (&mut self.bytes[self.pos..]).write(buf)?;
            self.pos += len_write;
        } else {
            // len_after > len_before
            let count_right = len_after - len_vec;
            self.bytes.reserve(count_right);

            if self.pos < len_vec {
                let count_left = len_append - count_right;
                _ = (&mut self.bytes[self.pos..]).write(&buf[0..count_left])?; // must equals count_left
                

                let mut bts = buf[count_left..].to_vec();
                self.bytes.append(&mut bts);


            } else {
                // self.pos == len_before
                let mut bts = buf.to_vec();
                self.bytes.append(&mut bts);
            }
            self.pos += len_append;
        }
        Ok(len_append)
        
    
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl io::Seek for BytesIO {
    fn seek(&mut self, pos_style: io::SeekFrom) -> io::Result<u64> {
        let (base_pos, offset) = match pos_style {
            io::SeekFrom::Start(n) => {
                self.pos = n as usize;
                return Ok(n);
            }
            io::SeekFrom::End(n) => (self.bytes.len(), n),
            io::SeekFrom::Current(n) => (self.pos, n),
        };
        let offset = offset as isize;
        match base_pos.checked_add_signed(offset) {
            Some(n) => {
                self.pos = n;
                Ok(self.pos as u64)
            }
            None => Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                "invalid seek to a negative or overflowing position",
            )),
        }
    }
}

impl io::BufRead for BytesIO {
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        Ok(self.bytes.as_slice())
    }

    fn consume(&mut self, amt: usize) {
        debug_assert!(self.pos + amt >= self.bytes.len(), "internal: inc_start out of bounds");
        self.pos += amt
    }
}